home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Pascal / Applications / NIH Image 1.60 / 1.60 Source / Stacks.p < prev    next >
Encoding:
Text File  |  1996-03-08  |  57.4 KB  |  2,142 lines  |  [TEXT/PJMM]

  1. unit Stacks;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, 
  7.         Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows,
  8.         Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, Processes,
  9.         QDOffscreen, Timer, PictUtils,
  10.         {Types, Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap, ToolUtils,
  11.         Resources, Errors, Palettes, QDOffscreen, PictUtils, Timer, Windows, TextUtils,}
  12.         globals, Utilities, Graphics, Analysis, Camera, file1, file2, filters, sound, lut;
  13.  
  14.     procedure MakeStack;
  15.     procedure MakeWindowsFromStack;
  16.     function AddSlice (update: boolean): boolean;
  17.     procedure DeleteSlice;
  18.     procedure ShowNextSlice (item: integer);
  19.     procedure ShowFirstOrLastSlice (ich: integer);
  20.     procedure DoStackInfo;
  21.     procedure Reslice;
  22.     procedure Animate;
  23.     procedure MakeMovie(ShowDialog: boolean);
  24.     procedure CaptureFrames;
  25.     procedure MakeMontage;
  26.     procedure ConvertRGBToEightBitColor (Capturing: boolean);
  27.     procedure ConvertEightBitColorToRGB;
  28.     procedure CaptureColor;
  29.     procedure AverageSlices;
  30.     procedure ConvertRGBToHSV;
  31.  
  32.  
  33. implementation
  34.  
  35.  
  36.     procedure MakeStack;
  37.         var
  38.             ok, isStack: boolean;
  39.             i, result: integer;
  40.             TempInfo, SaveInfo: InfoPtr;
  41.             str: str255;
  42.     begin
  43.         if not AllSameSize then begin
  44.                 PutError('All currently open images must be the same size to make a stack.');
  45.                 exit(MakeStack);
  46.             end;
  47.         isStack := false;
  48.         for i := 1 to nPics do begin
  49.                 TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
  50.                 isStack := isStack or (TempInfo^.StackInfo <> nil);
  51.             end;
  52.         if isStack then begin
  53.                 PutError('All stacks must be closed before making a new stack.');
  54.                 exit(MakeStack);
  55.             end;
  56.         if nPics > MaxSlices then begin
  57.                 NumToString(MaxSlices, str);
  58.                 PutError(concat('Maximun stack size is ', str, ' slices.'));
  59.                 exit(MakeStack);
  60.             end;
  61.         StopDigitizing;
  62.         DisableDensitySlice;
  63.         SelectWindow(PicWindow[1]);
  64.         Info := pointer(WindowPeek(PicWindow[1])^.RefCon);
  65.         ActivateWindow;
  66.         KillRoi;
  67.         UnZoom;
  68.         if not MakeStackFromWindow then
  69.             exit(MakeStack);
  70.         with info^ do begin
  71.                 StackInfo^.nSlices := nPics;
  72.                 title := 'Stack';
  73.                 UpdateTitleBar;
  74.                 Revertable := false;
  75.             end;
  76.         SaveInfo := Info;
  77.         MakingStack := true;
  78.         ShowWatch;
  79.         for i := 2 to nPics do begin
  80.                 TempInfo := pointer(WindowPeek(PicWindow[2])^.RefCon);
  81.                 with TempInfo^ do begin
  82.                         hunlock(PicBaseHandle);
  83.                         info^.StackInfo^.PicBaseH[i] := PicBaseHandle;
  84.                     end;
  85.                 result := CloseAWindow(PicWindow[2]);
  86.                 Info := SaveInfo;
  87.             end;
  88.         UpdateWindowsMenuItem;
  89.         MakingStack := false;
  90.     end;
  91.  
  92.  
  93.     procedure DeleteSlice;
  94.         var
  95.             SliceToDelete, NextSlice, i: integer;
  96.             isRoi: boolean;
  97.     begin
  98.         with info^, info^.StackInfo^ do begin
  99.                 if nSlices = 1 then begin
  100.                         WhatToUndo := NothingToUndo;
  101.                         exit(DeleteSlice);
  102.                     end;
  103.                 isRoi := RoiShowing;
  104.                 if isRoi then
  105.                     KillRoi;
  106.                 SetupUndo;
  107.                 WhatToUndo := UndoSliceDelete;
  108.                 SliceToDelete := CurrentSlice;
  109.                 if CurrentSlice = 1 then begin
  110.                         NextSlice := 2;
  111.                         WhatToUndo := UndoFirstSliceDelete;
  112.                     end
  113.                 else
  114.                     NextSlice := CurrentSlice - 1;
  115.                 SelectSlice(NextSlice);
  116.                 UpdatePicWindow;
  117.                 DisposeHandle(PicBaseH[SliceToDelete]);
  118.                 for i := SliceToDelete to nSlices - 1 do
  119.                     PicBaseH[i] := PicBaseH[i + 1];
  120.                 nSlices := nSlices - 1;
  121.                 if CurrentSlice <> 1 then
  122.                     CurrentSlice := CurrentSlice - 1;
  123.                 if (StackType = rgbStack) and (nSlices <> 3) then
  124.                     StackType := VolumeStack;
  125.                 UpdateTitleBar;
  126.                 if isRoi then
  127.                     RestoreRoi;
  128.                 changes := true;
  129.                 UpdateWindowsMenuItem;
  130.             end;
  131.     end;
  132.  
  133.  
  134.     procedure MakeWindowsFromStack;
  135.         var
  136.             i, ignore: integer;
  137.             N: LongInt;
  138.             SaveInfo: InfoPtr;
  139.             tmp: longint;
  140.  
  141.         function MakeName (i: integer): str255;
  142.             var
  143.                 str: str255;
  144.         begin
  145.             RealToString(i, 3, 0, str);
  146.             if str[1] = ' ' then
  147.                 str[1] := '0';
  148.             if str[2] = ' ' then
  149.                 str[2] := '0';
  150.             MakeName := str;
  151.         end;
  152.  
  153.     begin
  154.         N := info^.StackInfo^.nSlices;
  155.         tmp := SizeOf(PicInfo);
  156.         if MaxBlock < (MinFree + info^.ImageSize + (SizeOf(PicInfo) + 2000) * N) then begin
  157.                 PutError('There is not enough memory available to convert this stack to windows.');
  158.                 exit(MakeWindowsFromStack);
  159.             end;
  160.         SaveInfo := Info;
  161.         KillRoi;
  162.         for i := 1 to N - 1 do begin
  163.                 SelectSlice(1);
  164.                 info^.StackInfo^.CurrentSlice := 1;
  165.                 if not Duplicate(MakeName(i), false) then
  166.                     exit(MakeWindowsFromStack);
  167.                 info := SaveInfo;
  168.                 DeleteSlice;
  169.             end;
  170.         if Duplicate(MakeName(N), false) then begin
  171.                 info := SaveInfo;
  172.                 info^.changes := false;
  173.                 ignore := CloseAWindow(info^.wptr);
  174.             end;
  175.     end;
  176.  
  177.  
  178.     procedure ShowNextSlice (item: integer);
  179.         var
  180.             isRoi: boolean;
  181.     begin
  182.         with info^, info^.StackInfo^ do begin
  183.                 if item = NextSliceItem then begin
  184.                         CurrentSlice := CurrentSlice + 1;
  185.                         if CurrentSlice > nSlices then
  186.                             CurrentSlice := nSlices;
  187.                     end
  188.                 else begin
  189.                         CurrentSlice := CurrentSlice - 1;
  190.                         if CurrentSlice < 1 then
  191.                             CurrentSlice := 1;
  192.                     end;
  193.                 isRoi := RoiShowing;
  194.                 if isRoi then
  195.                     KillRoi;
  196.                 SelectSlice(CurrentSlice);
  197.                 UpdatePicWindow;
  198.                 UpdateTitleBar;
  199.                 WhatToUndo := NothingToUndo;
  200.                 isInsertionPoint:=false;
  201.                 if isRoi then
  202.                     RestoreRoi;
  203.             end;
  204.     end;
  205.  
  206.  
  207.     procedure ShowFirstOrLastSlice (ich: integer);
  208.         var
  209.             isRoi: boolean;
  210.     begin
  211.         with info^, info^.StackInfo^ do begin
  212.                 if ich = EndKey then
  213.                     CurrentSlice := nSlices
  214.                 else
  215.                     CurrentSlice := 1;
  216.                 isRoi := RoiShowing;
  217.                 if isRoi then
  218.                     KillRoi;
  219.                 SelectSlice(CurrentSlice);
  220.                 UpdatePicWindow;
  221.                 UpdateTitleBar;
  222.                 WhatToUndo := NothingToUndo;
  223.                 isInsertionPoint:=false;
  224.                 if isRoi then
  225.                     RestoreRoi;
  226.             end;
  227.     end;
  228.  
  229.  
  230.     procedure GetSlice (xstart, ystart, start: extended; angle: extended; count: integer; var line: LineType);
  231.         var
  232.             i: integer;
  233.             x, y, xinc, yinc: extended;
  234.             IntegerStart: boolean;
  235.     begin
  236.         IntegerStart := (xstart = trunc(xstart)) and (ystart = trunc(ystart));
  237.         if IntegerStart and (angle = 0.0) then begin
  238.                 GetLine(trunc(xstart), trunc(ystart), count, line);
  239.                 exit(GetSlice);
  240.             end;
  241.         if IntegerStart and (angle = 270.0) then begin
  242.                 GetColumn(trunc(xstart), trunc(ystart), count, line);
  243.                 exit(GetSlice);
  244.             end;
  245.         angle := (angle / 180.0) * pi;
  246.         xinc := cos(angle);
  247.         yinc := -sin(angle);
  248.         x := xstart + start * xinc;
  249.         y := ystart + start * yinc;
  250.         for i := 0 to count - 1 do begin
  251.                 line[i] := round(GetInterpolatedPixel(x, y));
  252.                 x := x + xinc;
  253.                 y := y + yinc;
  254.             end;
  255.     end;
  256.  
  257.  
  258.     function DoResliceOptions: boolean;
  259.     var
  260.         default, tmp: extended;
  261.         Canceled: boolean;
  262.         prompt, str: str255;
  263.     begin
  264.         with info^.StackInfo^, info^ do begin
  265.             if SpatiallyCalibrated then begin
  266.                 default := SliceSpacing / xScale;
  267.                 str := xUnit;
  268.             end else begin
  269.                 default := SliceSpacing;
  270.                 str := 'pixels';
  271.             end;
  272.             if SliceSpacing = 0.0 then
  273.                 default := 1.0;
  274.             tmp := GetReal(concat('Slice Spacing (', str, '):'), default, 2, Canceled);
  275.             if not Canceled and (tmp > 0.0) then begin
  276.                     if SpatiallyCalibrated then
  277.                         SliceSpacing := tmp * xScale
  278.                     else
  279.                         SliceSpacing := tmp;
  280.                 end;
  281.         end; {with}
  282.         DoResliceOptions := not canceled;
  283.     end;
  284.  
  285.  
  286.     procedure Reslice;
  287.         var
  288.             DstWidth, DstHeight, nSlices: integer;
  289.             dstLeft, dstTop, y, i, j, LineLength: integer;
  290.             SaveWindowFlag, SaveMacro, HorizontalMode: boolean;
  291.             SaveHScale, SaveVScale, UncalibratedLineLength, CalibratedLineLength, angle: extended;
  292.             Stack, Reconstruction: InfoPtr;
  293.             aLine: LineType;
  294.             name, str1, str2: str255;
  295.             MaskRect: rect;
  296.             x1, y1, x2, y2, ulength, clength: extended;
  297.  
  298.         procedure MakeRoi (Left, Top, Width, Height: integer);
  299.         begin
  300.             with info^ do begin
  301.                     RoiType := RectRoi;
  302.                     SetRect(RoiRect, left, top, left + width, top + height);
  303.                     MakeRegion;
  304.                     SetupUndo;
  305.                     RoiShowing := true;
  306.                 end;
  307.         end;
  308.  
  309.     begin
  310.         with info^, info^.StackInfo^ do begin
  311.                 if nSlices < 2 then begin
  312.                         PutError('Reslicing requires at least 2 slices.');
  313.                         AbortMacro;
  314.                         exit(Reslice);
  315.                     end;
  316.                 if not (RoiShowing and (RoiType = LineRoi)) then begin
  317.                         PutError('Please make a straight line selection first.');
  318.                         AbortMacro;
  319.                         exit(Reslice);
  320.                     end;
  321.                 Stack := info;
  322.                 GetLengthOrPerimeter(ulength, clength);
  323.                 LineLength := round(ulength);
  324.                 if LineLength = 0 then begin
  325.                         PutError('Line length cannot be zero.');
  326.                         AbortMacro;
  327.                         exit(Reslice);
  328.                     end;
  329.                 if SliceSpacing = 0.0 then
  330.                     if not DoResliceOptions then
  331.                         exit(reslice);;
  332.                 GetLoi(x1, y1, x2, y2);
  333.                 if (LAngle = 0.0) or (LAngle = 270.0) then
  334.                     if NotInBounds then
  335.                         exit(Reslice);
  336.                 HorizontalMode := not OptionKeyWasDown;
  337.                 if HorizontalMode then begin
  338.                         DstWidth := LineLength;
  339.                         DstHeight := round(nSlices * SliceSpacing);
  340.                         if DstHeight < nSlices then
  341.                             DstHeight := nSlices;
  342.                         dstLeft := 0;
  343.                         dstTop := round((dstHeight - nSlices) / 2.0);
  344.                     end
  345.                 else begin
  346.                         DstWidth := round(nSlices * SliceSpacing);
  347.                         if DstWidth < nSlices then
  348.                             DstWidth := nSlices;
  349.                         DstHeight := LineLength;
  350.                         dstLeft := round((dstWidth - nSlices) / 2.0);
  351.                         dstTop := 0;
  352.                     end;
  353.                 RealToString(y1, 3, 0, str1);
  354.                 RealToString(LAngle, 1, 2, str2);
  355.                 name := concat(str1, '-', str2);
  356.                 if not NewPicWindow(name, DstWidth, DstHeight) then
  357.                     exit(Reslice);
  358.                 Reconstruction := info;
  359.                 SaveWindowFlag := rsCreateNewWindow;
  360.                 SaveHScale := rsHScale;
  361.                 SaveVScale := rsVScale;
  362.                 rsCreateNewWindow := false;
  363.                 rsMethod := bilinear;
  364.                 for i := 1 to nSlices do begin
  365.                         Info := Stack;
  366.                         SelectSlice(i);
  367.                         GetSlice(x1, y1, 0.0, LAngle, LineLength, aLine);
  368.                         info := Reconstruction;
  369.                         if HorizontalMode then begin
  370.                                 PutLine(dstLeft, dstTop + nSlices - i, LineLength, aLine);
  371.                                 if i = 1 then {Draw extra line needed to get scaling to work right.}
  372.                                     PutLine(dstLeft, dstTop + nSlices, LineLength, aLine);
  373.                                 SetRect(MaskRect, dstLeft, dstTop + nSlices - i, dstLeft + LineLength, dstTop + nSlices - i + 1);
  374.                             end
  375.                         else begin
  376.                                 PutColumn(dstLeft + nSlices - i, dstTop, LineLength, aLine);
  377.                                 if i = 1 then {Draw extra line needed to get scaling to work right.}
  378.                                     PutLine(dstLeft + nSlices, dstTop, LineLength, aLine);
  379.                                 SetRect(MaskRect, dstLeft + nSlices - i, dstTop, dstLeft + nSlices - i + 1, dstTop + LineLength);
  380.                             end;
  381.                         UpdateScreen(MaskRect);
  382.                     end;
  383.                 if HorizontalMode then begin
  384.                         MakeRoi(dstLeft, dstTop, LineLength, nSlices);
  385.                         rsHScale := 1.0;
  386.                         rsVScale := SliceSpacing;
  387.                     end
  388.                 else begin
  389.                         MakeRoi(dstLeft, dstTop, nSlices, LineLength);
  390.                         rsHScale := SliceSpacing;
  391.                         rsVScale := 1.0;
  392.                     end;
  393.                 rsAngle := 0;
  394.                 SaveMacro := macro;
  395.                 macro := true;
  396.                 ScaleAndRotate;
  397.                 macro := SaveMacro;
  398.                 Info := Stack;
  399.                 SelectSlice(CurrentSlice);
  400.                 Info := Reconstruction;
  401.                 rsCreateNewWindow := SaveWindowFlag;
  402.                 rsHScale := SaveHScale;
  403.                 rsVScale := SaveVScale;
  404.                 KillRoi;
  405.             end;
  406.     end;
  407.  
  408.  
  409.     procedure Animate;
  410.         var
  411.             n, SaveN, fpsInterval, DelayCount: integer;
  412.             Event: EventRecord;
  413.             ch: char;
  414.             b: boolean;
  415.             SingleStep, GoForward, NewKeyDown, PhotoMode: boolean;
  416.             nFrames, StartTicks, NextTicks, SaveTicks, ticks: LongInt;
  417.             fps, seconds: extended;
  418.  
  419.         procedure ShowFPS (fps: extended);
  420.             var
  421.                 hstart, vstart, ivalue: integer;
  422.                 key: str255;
  423.         begin
  424.             if PhotoMode then
  425.                 exit(ShowFPS);
  426.             hstart := InfoHStart;
  427.             vstart := InfoVStart;
  428.             SetPort(InfoWindow);
  429.             MoveTo(xValueLoc, vstart);
  430.             case DelayTicks of
  431.                 0: 
  432.                     key := '9 ';
  433.                 2: 
  434.                     key := '8 ';
  435.                 3: 
  436.                     key := '7 ';
  437.                 4: 
  438.                     key := '6 ';
  439.                 6: 
  440.                     key := '5 ';
  441.                 8: 
  442.                     key := '4 ';
  443.                 12: 
  444.                     key := '3 ';
  445.                 30: 
  446.                     key := '2 ';
  447.                 60: 
  448.                     key := '1 ';
  449.             end;
  450.             if SingleStep then begin
  451.                     if GoForward then
  452.                         key := '->'
  453.                     else
  454.                         key := '<-';
  455.                 end;
  456.             DrawString(key);
  457.             MoveTo(yValueLoc, vstart + 10);
  458.             DrawReal(fps, 1, 2);
  459.             DrawChar(' ');
  460.         end;
  461.  
  462.     begin
  463.         if info^.StackInfo = nil then begin
  464.                 PutError('Animation requires a stack.');
  465.                 exit(Animate);
  466.             end;
  467.         with info^, info^.StackInfo^ do begin
  468.                 if nSlices < 2 then begin
  469.                         PutError('Animation requires at least two "slices".');
  470.                         exit(Animate);
  471.                     end;
  472.                 KillRoi;
  473.                 PhotoMode := OptionKeyDown or OptionKeyWasDown;
  474.                 if PhotoMode then
  475.                     EraseScreen
  476.                 else begin
  477.                         ShowWatch;
  478.                         ShowMessage(concat('Use 1...9 keys to control speed', crStr, 'Use arrow keys to single step', crStr, 'Press mouse button to stop'));
  479.                     end;
  480.                 FlushEvents(EveryEvent, 0);
  481.                 fpsInterval := 10;
  482.                 SaveN := -1;
  483.                 n := 1;
  484.                 GoForward := true;
  485.                 SingleStep := false;
  486.                 nFrames := 0;
  487.                 StartTicks := TickCount;
  488.                 NextTicks := StartTicks;
  489.                 SaveTicks := StartTicks;
  490.                 if not PhotoMode then begin
  491.                         DrawLabels('key:', 'fps:', '');
  492.                         SetPort(InfoWindow);
  493.                         TextSize(9);
  494.                         TextFont(Monaco);
  495.                         TextMode(SrcCopy);
  496.                     end;
  497.                 repeat
  498.                     b := WaitNextEvent(EveryEvent, Event, 0, nil);
  499.                     NewKeyDown := (event.what = KeyDown) or (event.what = AutoKey);
  500.                     if NewKeyDown then begin
  501.                             Ch := chr(BitAnd(Event.message, 127));
  502.                             SingleStep := false;
  503.                             case ord(ch) of
  504.                                 28, 44, 60, PageUp: {<-, <}
  505.                                     begin
  506.                                         SingleStep := true;
  507.                                         GoForward := false;
  508.                                         n := n - 1;
  509.                                         if n < 1 then
  510.                                             n := 1;
  511.                                         DelayTicks := 0
  512.                                     end; {left}
  513.                                 29, 46, 62, PageDown:  {->, >}
  514.                                     begin
  515.                                         SingleStep := true;
  516.                                         GoForward := true;
  517.                                         n := n + 1;
  518.                                         if n > nSlices then
  519.                                             n := nSlices;
  520.                                         DelayTicks := 0
  521.                                     end;  {right}
  522.                                 57: 
  523.                                     DelayTicks := 0;  {'9'-max speed}
  524.                                 56: 
  525.                                     DelayTicks := 2;  {'8'-30 fps}
  526.                                 55: 
  527.                                     DelayTicks := 3;  {'7'-20 fps}
  528.                                 54: 
  529.                                     DelayTicks := 4;  {'6'-15 fps}
  530.                                 53: 
  531.                                     DelayTicks := 6;  {'5'-10 fps}
  532.                                 52: 
  533.                                     DelayTicks := 8; {'4'-7.5 fps}
  534.                                 51: 
  535.                                     DelayTicks := 12; {'3'-5 fps}
  536.                                 50: 
  537.                                     DelayTicks := 30; {'2'-2 fps}
  538.                                 49: 
  539.                                     DelayTicks := 60; {'1'-1 fps}
  540.                                 otherwise
  541.                             end; {case}
  542.                             if DelayTicks > 12 then
  543.                                 fpsInterval := 2
  544.                             else if DelayTicks > 3 then
  545.                                 fpsInterval := 5
  546.                             else
  547.                                 fpsInterval := 10;
  548.                         end; {if NewKeyDown}
  549.                     if GoForward then begin
  550.                             if not SingleStep then
  551.                                 n := n + 1;
  552.                             if n > nSlices then begin
  553.                                     if OscillatingMovies then begin
  554.                                             n := nSlices - 1;
  555.                                             GoForward := false;
  556.                                         end
  557.                                     else
  558.                                         n := 1;
  559.                                 end;
  560.                         end
  561.                     else begin
  562.                             if not SingleStep then
  563.                                 n := n - 1;
  564.                             if n < 1 then begin
  565.                                     if OscillatingMovies then begin
  566.                                             n := 2;
  567.                                             Goforward := true;
  568.                                         end
  569.                                     else
  570.                                         n := nSlices;
  571.                                 end;
  572.                         end;
  573.                     CurrentSlice := n;
  574.                     SelectSlice(CurrentSlice);
  575.                     UpdatePicWindow;
  576.                     nFrames := nFrames + 1;
  577.                     if SingleStep then begin
  578.                             if (not OptionKeyWasDown) and (n <> SaveN) then begin
  579.                                     UpdateTitleBar;
  580.                                     SaveN := n;
  581.                                 end;
  582.                             ShowFPS(0.0);
  583.                         end
  584.                     else if (nFrames mod fpsInterval) = 0 then begin
  585.                             ticks := TickCount;
  586.                             seconds := (ticks - SaveTicks) / 60.0;
  587.                             if seconds <> 0.0 then
  588.                                 fps := fpsInterval / seconds
  589.                             else
  590.                                 fps := 0.0;
  591.                             ShowFPS(fps);
  592.                             SaveTicks := ticks;
  593.                         end;
  594.                     DelayCount := 0;
  595.                     if DelayTicks > 0 then begin
  596.                             repeat
  597.                                 ticks := TickCount;
  598.                             until ticks >= NextTicks;
  599.                             NextTicks := ticks + DelayTicks;
  600.                         end;
  601.                 until (event.what = MouseDown) or (event.what = osEvt);
  602.                 if PhotoMode then
  603.                     RestoreScreen;
  604.                 FlushEvents(EveryEvent, 0);
  605.                 UpdateTitleBar
  606.             end; {with}
  607.     end;
  608.  
  609.  
  610.     function Activate (name: str255): boolean;
  611.   {Activates the window with the specified name.}
  612.         var
  613.             i: integer;
  614.             TempInfo: InfoPtr;
  615.     begin
  616.         Activate := false;
  617.         for i := 1 to nPics do begin
  618.                 TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
  619.                 if TempInfo^.title = name then begin
  620.                         if PicWindow[i] <> nil then begin
  621.                                 SelectWindow(PicWindow[i]);
  622.                                 Info := TempInfo;
  623.                                 ActivateWindow;
  624.                                 Activate := true;
  625.                             end; {if}
  626.                         leave;
  627.                     end; {if}
  628.             end; {for}
  629.     end;
  630.  
  631.  
  632.     function DoMakeMovieOptions: boolean;
  633.     const
  634.         FramesID = 3;
  635.         IntervalID = 5;
  636.         rateID = 7;
  637.         BlindID = 9;
  638.         LG3BufferID = 10;
  639.         StampID = 11;
  640.         UseExistingStackID = 12;
  641.         TriggerID = 13;
  642.         TriggerFirstID = 14;
  643.         TriggerEachID = 15;
  644.     var
  645.         mylog: DialogPtr;
  646.         item, i: integer;
  647.         FramesPerSecond: extended;
  648.         
  649.         procedure ShowFrameRate;
  650.         begin
  651.             if SecondsPerFrame = 0.0 then begin
  652.                 if fgWidth = 640 then
  653.                     FramesPerSecond := 30.0
  654.                 else FramesPerSecond := 25.0
  655.             end else
  656.                 FramesPerSecond := 1.0 / SecondsPerFrame;
  657.             if FramesPerSecond = trunc(FramesPerSecond) then
  658.                 SetDReal(MyLog, rateID, FramesPerSecond, 0)
  659.             else
  660.                 SetDReal(MyLog, rateID, FramesPerSecond, 4);
  661.         end;
  662.         
  663.         procedure ShowInterval;
  664.         begin
  665.             if SecondsPerFrame < 1.0 then
  666.                 SetDReal(MyLog, IntervalID, SecondsPerFrame, 4)
  667.             else if SecondsPerFrame < 99.0 then
  668.                 SetDReal(MyLog, IntervalID, SecondsPerFrame, 2)
  669.             else
  670.                 SetDReal(MyLog, IntervalID, SecondsPerFrame, 0);
  671.         end;
  672.         
  673.         procedure ShowTriggerMode;
  674.         begin
  675.             SetDlogItem(mylog, TriggerID, ord(ExternalTrigger));
  676.             SetDlogItem(mylog, TriggerFirstID, ord(TriggerFirstFrameOnly));
  677.             SetDlogItem(mylog, TriggerEachID, ord(not TriggerFirstFrameOnly));
  678.         end;
  679.         
  680.     begin
  681.         InitCursor;
  682.         mylog := GetNewDialog(230, nil, pointer(-1));
  683.         SetDNum(MyLog, FramesID, FramesWanted);
  684.         ShowFrameRate;
  685.         ShowInterval;
  686.         SetDlogItem(mylog, BlindID, ord(BlindMovieCapture));
  687.         SetDlogItem(mylog, LG3BufferID, ord(LG3BufferCapture));
  688.         SetDlogItem(mylog, StampID, ord(TimeStamp));
  689.         ShowTriggerMode;
  690.         SetDlogItem(mylog, UseExistingStackID, ord(UseExistingStack));
  691.         SelectDialogItemText(MyLog, FramesID, 0, 32767);
  692.         OutlineButton(MyLog, ok, 16);
  693.         repeat
  694.             ModalDialog(nil, item);
  695.             if item = FramesID then
  696.                 FramesWanted := GetDNum(MyLog, FramesID);
  697.             if item = IntervalID then begin
  698.                 SecondsPerFrame := GetDReal(MyLog, IntervalID);
  699.                 ShowFrameRate;
  700.             end;
  701.             if item = rateID then begin
  702.                 FramesPerSecond := GetDReal(MyLog, rateID);
  703.                 if FramesPerSecond <> 0.0 then
  704.                   SecondsPerFrame := 1.0 / FramesPerSecond;
  705.                 ShowInterval;
  706.             end;
  707.             if item = BlindID then begin
  708.                     BlindMovieCapture := not BlindMovieCapture;
  709.                     SetDlogItem(mylog, BlindID, ord(BlindMovieCapture));
  710.                 end;
  711.             if item = LG3BufferID then begin
  712.                     LG3BufferCapture := not LG3BufferCapture;
  713.                     if LG3BufferCapture then
  714.                         BlindMovieCapture := true;
  715.                     SetDlogItem(mylog, LG3BufferID, ord(LG3BufferCapture));
  716.                     SetDlogItem(mylog, BlindID, ord(BlindMovieCapture));
  717.                 end;
  718.             if item = StampID then begin
  719.                     TimeStamp := not TimeStamp;
  720.                     SetDlogItem(mylog, StampID, ord(TimeStamp));
  721.                 end;
  722.             if item = TriggerID then begin
  723.                 ExternalTrigger := not ExternalTrigger;
  724.                 SetDlogItem (mylog, TriggerID, ord (ExternalTrigger));
  725.               end;
  726.             if (item = TriggerFirstID) or (item = TriggerEachID) then begin
  727.                 TriggerFirstFrameOnly := not TriggerFirstFrameOnly;
  728.                 ExternalTrigger := true;
  729.                 ShowTriggerMode;
  730.               end;
  731.             if item = UseExistingStackID then begin
  732.                     UseExistingStack := not UseExistingStack;
  733.                     SetDlogItem(mylog, UseExistingStackID, ord(UseExistingStack));
  734.                 end;
  735.         until (item = ok) or (item = cancel);
  736.         DisposeDialog(mylog);
  737.         if FramesWanted < 1 then
  738.             FramesWanted := 1;
  739.         if FramesWanted > MaxSlices then
  740.             FramesWanted := MaxSlices;
  741.         if SecondsPerFrame < 0.0 then
  742.             SecondsPerFrame := 0.0;
  743.         if LG3BufferCapture and (item <> cancel) then begin
  744.             if FrameGrabber <> ScionLG3 then begin
  745.                 LG3BufferCapture := false;
  746.                 PutError('Capturing to an on-board frame buffer requires a Scion LG-3.');
  747.                 DoMakeMovieOptions := false;
  748.                 exit(DoMakeMovieOptions);
  749.             end;
  750.             if PCIFrameGrabber then begin
  751.                 LG3BufferCapture := false;
  752.                 PutError('On-board capture not supported on PCI frame grabbers.');
  753.                 DoMakeMovieOptions := false;
  754.                 exit(DoMakeMovieOptions);
  755.             end;
  756.             if FramesWanted > MaxLG3Frames then begin
  757.                 FramesWanted := MaxLG3Frames;
  758.                 PutError(concat('This ', long2str(MaxLG3Frames div 2), 'MB LG-3 can capture a maximum of ', long2str(MaxLG3Frames), ' frames to its on-board buffer.'));
  759.                 DoMakeMovieOptions := false;
  760.                 exit(DoMakeMovieOptions);
  761.             end;
  762.         end;
  763.         DoMakeMovieOptions := item <> cancel;
  764.     end;
  765.  
  766.  
  767.     procedure CaptureFramesUsingTicks(SecondsPerFrame:extended; nFrames:integer; frect:rect);
  768.     var
  769.         StartTicks, NextTicks, LastTicks, interval, ticks: LongInt;
  770.         SourcePixMap: PixMapHandle;
  771.         str: str255;
  772.         frame, i: integer;
  773.         ElapsedTime, avgFrameInterval: extended;
  774.     begin
  775.         interval := round(60.0 * SecondsPerFrame);
  776.         ShowWatch;
  777.         SourcePixMap := fgPixMap;
  778.         ResetFrameGrabber;
  779.         ShowTriggerMessage;
  780.         with info^, info^.StackInfo^ do begin
  781.                 if Interval >= 30 then
  782.                     ShowMessage(CmdPeriodToStop)
  783.                 else
  784.                     DrawLabels('Frame:', 'Total:', '');
  785.                 if TimeStamp then begin
  786.                     SetPort(GrafPtr(osPort));
  787.                     TextFont(Monaco);
  788.                     TextSize(9);
  789.                 end;
  790.                 for frame := 1 to nFrames do begin
  791.                         CurrentSlice := frame;
  792.                         SelectSlice(CurrentSlice);
  793.                         if Interval >= 30 then
  794.                             UpdateTitleBar
  795.                         else
  796.                             Show2Values(CurrentSlice, nSlices);
  797.                         GetFrame;
  798.                         ticks:=TickCount;
  799.                         if (frame = 1) then begin
  800.                             StartTicks := ticks;
  801.                             NextTicks := StartTicks+interval - 3;
  802.                             if TriggerFirstFrameOnly then
  803.                                 ExternalTrigger := false;
  804.                         end else
  805.                             NextTicks := NextTicks + interval;
  806.                         if frame = nFrames then
  807.                             LastTicks := ticks;
  808.                         CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  809.                         if TimeStamp then begin
  810.                             ElapsedTime:=(ticks-StartTicks) / 60.0;
  811.                             RealToString(ElapsedTime, 9, 3, str);
  812.                             for i:=1 to 5 do
  813.                                 if str[i]=' ' then str[i]:='0';
  814.                             MoveTo(2,10);
  815.                             DrawString(str);
  816.                             PlotData^[frame]:=ElapsedTime;
  817.                         end;
  818.                         if not BlindMovieCapture then
  819.                             UpdatePicWindow;
  820.                         while TickCount < NextTicks do
  821.                             if CommandPeriod then begin
  822.                                     beep;
  823.                                     wait(60);
  824.                                     exit(CaptureFramesUsingTicks);
  825.                                 end;
  826.                     end; {for}
  827.                 ElapsedTime := (LastTicks - StartTicks) / 60.0;
  828.                 avgFrameInterval := ElapsedTime / (nFrames - 1);
  829.                 FrameInterval := avgFrameInterval;
  830.             end; {with}
  831.     end;
  832.  
  833.  
  834.  
  835.     procedure DrawTimeStamps(nFrames: integer);
  836.     var
  837.         frame, i: integer;
  838.         str: str255;
  839.         SaveGDevice: GDHandle;
  840.     begin
  841.         with info^, info^.StackInfo^ do begin
  842.             SaveGDevice := GetGDevice;
  843.             SetGDevice(osGDevice);
  844.             SetPort(GrafPtr(osPort));
  845.             TextFont(Monaco);
  846.             TextSize(9);
  847.             for frame := 1 to nFrames do begin
  848.                 ShowAnimatedWatch;
  849.                 CurrentSlice := frame;
  850.                 SelectSlice(CurrentSlice);
  851.                 RealToString(PlotData^[frame], 9, 3, str);
  852.                 for i:=1 to 5 do
  853.                     if str[i]=' ' then str[i]:='0';
  854.                 MoveTo(2,10);
  855.                 DrawString(str);
  856.             end; {for}
  857.             SetGDevice(SaveGDevice);
  858.         end;
  859.     end;
  860.  
  861.  
  862.     function uTickCount:extended;
  863.     var
  864.         count:UnsignedWide;
  865.         d:extended;
  866.     begin
  867.         microseconds(count);
  868.         d:=count.lo;
  869.         if d<0 then d:=band(count.lo,$7fffffff)+2147483648.0;
  870.         uTickCount:=d+count.hi*4294967296.0;
  871.     end;
  872.  
  873.  
  874.     procedure CaptureFramesUsingMicroTicks(SecondsPerFrame:extended; nFrames:integer; frect:rect);
  875.     var
  876.         uStartTicks, uNextTicks, uLastTicks, uInterval, uTicks: Extended;
  877.         SourcePixMap: PixMapHandle;
  878.         frame, i: integer;
  879.         ElapsedTime: extended;
  880.         uTicksToCaptureOneFrame, avgFrameInterval:extended;
  881.         ShowProgress: boolean;
  882.     begin
  883.         ShowWatch;
  884.         uInterval := 1000000.0 * SecondsPerFrame;
  885.         SourcePixMap := fgPixMap;
  886.         ResetFrameGrabber;
  887.         if PCIFrameGrabber then begin
  888.             DoubleBuffering := true;
  889.             LG3BufferCapture := false;
  890.             CurrentBufferIsZero := true;
  891.         end;
  892.         ShowTriggerMessage;
  893.         if fgWidth = 768 then  {if PAL board}
  894.             uTicksToCaptureOneFrame := 40000.0  {PAL captures 25 fps}
  895.         else
  896.             uTicksToCaptureOneFrame := 33333.0;  {non-PAL captures 33 fps}
  897.         ShowProgress := ((not LG3BufferCapture) and (not DoubleBuffering)) or (uInterval > (2 * uTicksToCaptureOneFrame));
  898.         with info^, info^.StackInfo^ do begin
  899.                 if ShowProgress and (uInterval < 500000.0) then
  900.                     DrawLabels('Frame:', 'Total:', '')
  901.                 else if not ExternalTrigger then
  902.                     ShowMessage(CmdPeriodToStop);
  903.                 for frame := 1 to nFrames do begin
  904.                     CurrentSlice := frame;
  905.                     if DoubleBuffering and (frame > 1) then {??}
  906.                         SelectSlice(CurrentSlice - 1)
  907.                     else
  908.                         SelectSlice(CurrentSlice);
  909.                     if showProgress then begin
  910.                         if uInterval >= 500000.0 then
  911.                             UpdateTitleBar
  912.                         else
  913.                             Show2Values(CurrentSlice, nSlices);
  914.                     end;
  915.                     if DoubleBuffering then begin
  916.                         StartFrame;
  917.                         if frame <> 1 then
  918.                             CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  919.                         StopFrame;
  920.                         uTicks := uTickCount;
  921.                     end else if LG3BufferCapture then begin
  922.                         BufferReg^ := frame - 1;
  923.                         GetFrame;
  924.                         uTicks := uTickCount;
  925.                     end else begin
  926.                         GetFrame;
  927.                         uTicks := uTickCount;
  928.                         CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  929.                     end;
  930.                     if frame = 1 then begin
  931.                         uStartTicks := uTicks;
  932.                         uNextTicks := uStartTicks + uInterval - 1.5 * uTicksToCaptureOneFrame;
  933.                         if TriggerFirstFrameOnly then
  934.                             ExternalTrigger := false;
  935.                     end else
  936.                         uNextTicks :=uNextTicks + uInterval;
  937.                     if frame = nFrames then
  938.                         uLastTicks := uTicks;
  939.                     if TimeStamp then begin
  940.                         ElapsedTime:=(uTicks-uStartTicks) / 1000000.0;
  941.                         PlotData^[frame]:=ElapsedTime;
  942.                     end;
  943.                     if not BlindMovieCapture then
  944.                         UpdatePicWindow;
  945.                     if uTicks < uNextTicks then
  946.                         while uTickCount < uNextTicks do
  947.                             if CommandPeriod then begin
  948.                                     beep;
  949.                                     wait(60);
  950.                                     exit(CaptureFramesUsingMicroTicks);
  951.                                 end;
  952.                     end; {for}
  953.                 ElapsedTime := (uLastTicks - uStartTicks) / 1000000.0;
  954.                 avgFrameInterval := ElapsedTime / (nFrames - 1);
  955.                 FrameInterval := avgFrameInterval;
  956.             end; {with}
  957.         if LG3BufferCapture then begin
  958.             {Copy captured frames from LG-3 to stack.}
  959.             with info^, info^.StackInfo^ do begin
  960.                 for frame := 1 to nFrames do begin
  961.                     ShowAnimatedWatch;
  962.                     CurrentSlice := frame;
  963.                     SelectSlice(CurrentSlice);
  964.                     BufferReg^ := frame - 1;
  965.                     CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  966.                 end; {for}
  967.             end; {with}
  968.             BufferReg^ := 0;
  969.         end; {if LG3BufferCapture}
  970.         if DoubleBuffering then with info^, info^.StackInfo^ do begin
  971.             CurrentSlice := nframes;
  972.             SelectSlice(CurrentSlice);
  973.             CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  974.             BufferReg^ := 0;
  975.             CurrentBufferIsZero := true;
  976.             DoubleBuffering := false;
  977.             with fgPort^.PortPixMap^^ do
  978.                 BaseAddr := ptr(fgSuperSlotBase0);
  979.         end;
  980.         if TimeStamp then
  981.             DrawTimeStamps(nFrames);
  982.     end;
  983.  
  984.     
  985.     
  986.     procedure MakeMovie(ShowDialog: boolean);
  987.         var
  988.             nFrames, wleft, wtop, width, height: integer;
  989.             ignore, SaveFW: integer;
  990.             OutOfMemory: boolean;
  991.             seconds: extended;
  992.             frect: rect;
  993.             Canceled: boolean;
  994.             avgFrameInterval: extended;
  995.     begin
  996.         SelectCameraWindow;
  997.         with info^ do begin
  998.             if PictureType <> FrameGrabberType then begin
  999.                     PutError('You must be capturing to make a movie.');
  1000.                     exit(MakeMovie);
  1001.                 end;
  1002.             StopDigitizing;
  1003.             if not (RoiShowing and (RoiType = RectRoi)) then begin
  1004.                     PutError('Please make a rectangular selection first.');
  1005.                     exit(MakeMovie);
  1006.                 end;
  1007.             if NotInBounds then
  1008.                 exit(MakeMovie);
  1009.             if ShowDialog then
  1010.                 if not DoMakeMovieOptions then begin
  1011.                     AbortMacro;
  1012.                     exit(MakeMovie);
  1013.                 end;
  1014.             if (FrameGrabber <> ScionLG3) then
  1015.                 LG3BufferCapture := false;
  1016.             if LG3BufferCapture and (FramesWanted > MaxLG3Frames) then
  1017.                 FramesWanted := MaxLG3Frames;
  1018.             if LG3BufferCapture then
  1019.                 BlindMovieCapture := true;
  1020.             with RoiRect do begin
  1021.                     left := band(left + 1, $fffc);   {Word align}
  1022.                     right := band(right + 2, $fffc);
  1023.                     if right > PicRect.right then
  1024.                         right := PicRect.right;
  1025.                     MakeRegion;
  1026.                     wleft := left;
  1027.                     wtop := top;
  1028.                     width := right - left;
  1029.                     height := bottom - top;
  1030.                 end;
  1031.             end; {with info^}
  1032.         with frect do begin
  1033.                 left := wleft;
  1034.                 top := wtop;
  1035.                 right := left + width;
  1036.                 bottom := top + height;
  1037.             end;
  1038.         if UseExistingStack then begin
  1039.             if not Activate('Movie') then begin
  1040.                 PutError('Can''t find a stack named "Movie".');
  1041.                 UseExistingStack := false;
  1042.                 AbortMacro;
  1043.                 exit(MakeMovie);
  1044.             end;
  1045.             with info^ do begin
  1046.                 if (PixelsPerLine <> width) or (nLines <> height) then begin
  1047.                     PutError('The dimensions of the stack "Movie" are not the same as the selection.');
  1048.                     exit(MakeMovie);
  1049.                 end;
  1050.                 nFrames := StackInfo^.nSlices;
  1051.                 if nFrames > FramesWanted then
  1052.                     nFrames := FramesWanted;
  1053.             end {with info}
  1054.         end else begin
  1055.             if not NewPicWindow('Movie', width, height) then
  1056.                 exit(MakeMovie);
  1057.             if not MakeStackFromWindow then
  1058.                 exit(MakeMovie);
  1059.             nFrames := 1;
  1060.             OutOfMemory := false;
  1061.             while (nFrames < FramesWanted) and (not OutOfMemory) do begin
  1062.                     OutOfMemory := not AddSlice(false);
  1063.                     if not OutOfMemory then
  1064.                         nFrames := nFrames + 1;
  1065.                 end;
  1066.         end;
  1067.         if ExternalTrigger and not TriggerFirstFrameOnly then
  1068.             SecondsPerFrame := 0.0;
  1069.         If (FramesWanted < 1) then
  1070.             FramesWanted := 1;
  1071.         if SecondsPerFrame < 0.0 then
  1072.             SecondsPerFrame := 0.0;
  1073.         with info^.StackInfo^ do begin
  1074.             FrameInterval := 0.0;
  1075.             StackType := movieStack;
  1076.         end;
  1077.         if OptionKeyWasDown then
  1078.             CaptureFramesUsingTicks(SecondsPerFrame, nFrames, frect)
  1079.         else
  1080.             CaptureFramesUsingMicroTicks(SecondsPerFrame, nFrames, frect);
  1081.         ShowFirstOrLastSlice(HomeKey);
  1082.         avgFrameInterval := info^.StackInfo^.FrameInterval;
  1083.         if AvgFrameInterval <> 0.0 then
  1084.             ShowMessage(StringOf(nFrames:1, ' frames', cr,
  1085.                 AvgFrameInterval * nFrames:1:2, ' seconds', cr,
  1086.                 AvgFrameInterval:1:3, ' seconds/frame', cr,
  1087.                 1 / AvgFrameInterval:1:2, ' frames/second'));
  1088.         if TimeStamp then begin
  1089.             PlotData^[0] := nFrames;
  1090.             PlotData^[nFrames + 1] := SecondsPerFrame;
  1091.             PlotCount := 0;
  1092.         end;
  1093.     end;
  1094.  
  1095.  
  1096.     procedure CaptureFrames;
  1097.         var
  1098.             nFrames, wleft, wtop, width, height, i: integer;
  1099.             ignore, SaveFW: integer;
  1100.             OutOfMemory, AdvanceFrame, b: boolean;
  1101.             frect: rect;
  1102.             MainDevice: GDHandle;
  1103.             SourcePixMap: PixMapHandle;
  1104.             Event: EventRecord;
  1105.             ShutterSound: SndListHandle;
  1106.             err: OSErr;
  1107.  
  1108.         procedure CheckButton;
  1109.         begin
  1110.             if Button and not AdvanceFrame then
  1111.                 with Info^.StackInfo^ do begin
  1112.                         AdvanceFrame := true;
  1113.                         ShutterSound := SndListHandle(GetResource('snd ', 100));
  1114.                         if ShutterSound <> nil then
  1115.                             err := SndPlay(nil, ShutterSound, false);
  1116.                         if CurrentSlice < nSlices then begin
  1117.                                 CurrentSlice := CurrentSlice + 1;
  1118.                                 UpdateTitleBar;
  1119.                                 CurrentSlice := CurrentSlice - 1;
  1120.                             end;
  1121.                     end;
  1122.         end;
  1123.  
  1124.     begin
  1125.         with info^ do begin
  1126.                 if PictureType <> FrameGrabberType then begin
  1127.                         PutError('You must be capturing to capture frames.');
  1128.                         exit(CaptureFrames);
  1129.                     end;
  1130.                 StopDigitizing;
  1131.                 if not (RoiShowing and (RoiType = RectRoi)) then begin
  1132.                         PutError('Please make a rectangular selection first.');
  1133.                         exit(CaptureFrames);
  1134.                     end;
  1135.                 if NotInBounds then
  1136.                     exit(CaptureFrames);
  1137.                 SaveFW := FramesWanted;
  1138.                 ShutterSound := nil;
  1139.                 with RoiRect do begin
  1140.                         left := band(left + 1, $fffc);   {Word align}
  1141.                         right := band(right + 2, $fffc);
  1142.                         if right > PicRect.right then
  1143.                             right := PicRect.right;
  1144.                         MakeRegion;
  1145.                         wleft := left;
  1146.                         wtop := top;
  1147.                         width := right - left;
  1148.                         height := bottom - top;
  1149.                     end;
  1150.             end; {with info^}
  1151.         with frect do begin
  1152.                 left := wleft;
  1153.                 top := wtop;
  1154.                 right := left + width;
  1155.                 bottom := top + height;
  1156.             end;
  1157.         if not NewPicWindow('Frames', width, height) then
  1158.             exit(CaptureFrames);
  1159.         if not MakeStackFromWindow then
  1160.             exit(CaptureFrames);
  1161.         UpdateTitleBar;
  1162.         ShowWatch;
  1163.         SourcePixMap := fgPixMap;
  1164.         ResetFrameGrabber;
  1165.         FlushEvents(EveryEvent, 0);
  1166.         ExternalTrigger := false;
  1167.         UpdateVideoControl;
  1168.         with info^, info^.StackInfo^ do begin
  1169.                 ShowMessage(CmdPeriodToStop);
  1170.                 OutOfMemory := false;
  1171.                 AdvanceFrame := false;
  1172.                 while (not OutOfMemory) and (CurrentSlice <= MaxSlices) do begin
  1173.                         if AdvanceFrame then begin
  1174.                                 OutOfMemory := not AddSlice(false);
  1175.                                 AdvanceFrame := false;
  1176.                             end;
  1177.                         GetFrame;
  1178.                         CheckButton;
  1179.                         CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  1180.                         CheckButton;
  1181.                         UpdatePicWindow;
  1182.                         CheckButton;
  1183.                         b := WaitNextEvent(EveryEvent, Event, 0, nil);
  1184.                         if event.what = KeyDown then
  1185.                             leave;
  1186.                     end; {while}
  1187.             end; {with}
  1188.         if ShutterSound <> nil then
  1189.             ReleaseResource(handle(ShutterSound));
  1190.     end;
  1191.  
  1192.  
  1193.  
  1194.     procedure CopyPics (sPort, dPort: cGrafPtr; sRect, dRect: rect);
  1195.     begin
  1196.         pmForeColor(BlackIndex);
  1197.         pmBackColor(WhiteIndex);
  1198.         CopyBits(BitMapHandle(sPort^.portPixMap)^^, BitMapHandle(dPort^.PortPixMap)^^, sRect, dRect, SrcCopy, nil);
  1199.         pmForeColor(ForegroundIndex);
  1200.         pmBackColor(BackgroundIndex);
  1201.     end;
  1202.  
  1203.  
  1204.     procedure MakeMontage;
  1205.   {Opens a new window and creates a composite image}
  1206.   {from the slices in the current stack.}
  1207.     const
  1208.         ColumnsID = 3;
  1209.         RowsID = 4;
  1210.         ScaleID = 5;
  1211.         FirstID = 6;
  1212.         LastID = 7;
  1213.         IncrementID = 8;
  1214.         NumberID = 9;
  1215.         BordersID=16;
  1216.     var
  1217.         mylog: DialogPtr;
  1218.         item, i, nRows, nColumns, Inc, slices: integer;
  1219.         StackWidth, StackHeight, mWidth, mHeight, Background: integer;
  1220.         dWidth, dHeight, dLeft, dTop, dRight, dBottom, MaxWidth, MaxHeight: integer;
  1221.         FirstSlice, LastSlice, TotalSlices: integer;
  1222.         scale, SaveScale: extended;
  1223.         sPort, dPort: cGrafPtr;
  1224.         StackInfo, MontageInfo: InfoPtr;
  1225.         sRect, dRect: rect;
  1226.         IncrementSet: boolean;
  1227.         str: str255;
  1228.         loc: point;
  1229.         SaveGDevice: GDHandle;
  1230.         
  1231.     procedure Estimate (var scale:extended{ppc-bug}; adjustinc: boolean);
  1232.         var
  1233.             tmp, xxScale, yyScale: extended;
  1234.             n: integer;
  1235.     begin
  1236.         slices := LastSlice - FirstSlice + 1;
  1237.         if adjustinc then
  1238.             inc := 0;
  1239.         repeat
  1240.             if adjustinc then
  1241.                 inc := inc + 1;
  1242.             n := trunc(slices / inc);
  1243.             tmp := sqrt(n);
  1244.             if trunc(tmp) <> tmp then
  1245.                 tmp := trunc(tmp) + 1.0;
  1246.             nColumns := trunc(tmp);
  1247.             nRows := nColumns;
  1248.             if (nColumns * (nRows - 1)) >= n then
  1249.                 nRows := nRows - 1;
  1250.             xxScale := (MaxWidth / nColumns) / StackWidth;
  1251.             yyScale := (MaxHeight / nRows) / StackHeight;
  1252.             if xxScale < yyScale then
  1253.                 scale := xxScale
  1254.             else
  1255.                 scale := yyScale;
  1256.             if scale > 1.0 then
  1257.                 scale := 1.0;
  1258.             SaveScale := scale;
  1259.         until (scale >= 0.5) or (inc >= 3) or not adjustinc;
  1260.     end;
  1261.  
  1262.     begin
  1263.         InitCursor;
  1264.         with info^ do begin
  1265.                 StackWidth := PixelsPerLine;
  1266.                 StackHeight := nLines;
  1267.                 FirstSlice := 1;
  1268.                 TotalSlices := StackInfo^.nSlices;
  1269.                 LastSlice := TotalSlices;
  1270.             end;
  1271.         MaxWidth := ScreenWidth - 85;
  1272.         MaxHeight := ScreenHeight - 45;
  1273.         Estimate(scale, true);
  1274.         IncrementSet := false;
  1275.         mylog := GetNewDialog(150, nil, pointer(-1));
  1276.         SetDNum(MyLog, RowsID, nRows);
  1277.         SetDNum(MyLog, ColumnsID, nColumns);
  1278.         SetDReal(MyLog, ScaleID, scale, 2);
  1279.         SetDNum(MyLog, FirstID, FirstSlice);
  1280.         SetDNum(MyLog, LastID, LastSlice);
  1281.         SetDNum(MyLog, IncrementID, inc);
  1282.         SetDlogItem(MyLog, NumberID, ord(gNumberSlices));
  1283.         SetDlogItem(MyLog, BordersID, ord(gBorders));
  1284.         OutlineButton(MyLog, ok, 16);
  1285.         repeat
  1286.             ModalDialog(nil, item);
  1287.             if item = ColumnsID then begin
  1288.                     nColumns := GetDNum(MyLog, ColumnsID);
  1289.                     if nColumns < 0 then begin
  1290.                             nColumns := 0;
  1291.                             SetDNum(MyLog, ColumnsID, nRows);
  1292.                         end;
  1293.                 end;
  1294.             if item = RowsID then begin
  1295.                     nRows := GetDNum(MyLog, RowsID);
  1296.                     if nRows < 0 then begin
  1297.                             nRows := 0;
  1298.                             SetDNum(MyLog, RowsID, nRows);
  1299.                         end;
  1300.                 end;
  1301.             if item = ScaleID then
  1302.                 scale := GetDReal(MyLog, ScaleID);
  1303.             if item = FirstID then begin
  1304.                     FirstSlice := GetDNum(MyLog, FirstID);
  1305.                     if (FirstSlice < 1) or (FirstSlice > LastSlice) then
  1306.                         FirstSlice := 1;
  1307.                     if IncrementSet then
  1308.                         Estimate(scale, false)
  1309.                     else
  1310.                         Estimate(scale, true);
  1311.                     SetDNum(MyLog, RowsID, nRows);
  1312.                     SetDNum(MyLog, ColumnsID, nColumns);
  1313.                     SetDReal(MyLog, ScaleID, scale, 2);
  1314.                 end;
  1315.             if item = LastID then begin
  1316.                     LastSlice := GetDNum(MyLog, LastID);
  1317.                     if (LastSlice < FirstSlice) or (LastSlice > TotalSlices) then
  1318.                         LastSlice := TotalSlices;
  1319.                     if IncrementSet then
  1320.                         Estimate(scale, false)
  1321.                     else
  1322.                         Estimate(scale, true);
  1323.                     SetDNum(MyLog, RowsID, nRows);
  1324.                     SetDNum(MyLog, ColumnsID, nColumns);
  1325.                     SetDReal(MyLog, ScaleID, scale, 2);
  1326.                 end;
  1327.             if item = IncrementID then begin
  1328.                     inc := GetDNum(MyLog, IncrementID);
  1329.                     IncrementSet := true;
  1330.                     if (inc < 1) or (inc > (slices div 2)) then begin
  1331.                             inc := 1;
  1332.                             SetDNum(MyLog, IncrementID, inc);
  1333.                         end;
  1334.                     Estimate(scale, false);
  1335.                     SetDNum(MyLog, RowsID, nRows);
  1336.                     SetDNum(MyLog, ColumnsID, nColumns);
  1337.                     SetDReal(MyLog, ScaleID, scale, 2);
  1338.                 end;
  1339.             if item = NumberID then begin
  1340.                     gNumberSlices := not gNumberSlices;
  1341.                     SetDlogItem(MyLog, NumberID, ord(gNumberSlices));
  1342.                 end;
  1343.             if item = BordersID then begin
  1344.                     gBorders := not gBorders;
  1345.                     SetDlogItem(MyLog, BordersID, ord(gBorders));
  1346.                 end;
  1347.         until (item = ok) or (item = cancel);
  1348.         DisposeDialog(mylog);
  1349.         if item = cancel then
  1350.             exit(MakeMontage);
  1351.         if (scale <= 0.05) or (scale > 5) then
  1352.             scale := SaveScale;
  1353.         dWidth := round(StackWidth * scale);
  1354.         dHeight := round(StackHeight * scale);
  1355.         mWidth := nColumns * dWidth;
  1356.         mHeight := nRows * dHeight;
  1357.         StackInfo := info;
  1358.         Background := MyGetPixel(0, 0);
  1359.         SetBackgroundColor(Background);
  1360.         if Background = WhiteIndex then
  1361.             SetForegroundColor(BlackIndex)
  1362.         else
  1363.             SetForegroundColor(WhiteIndex);
  1364.         if not NewPicWindow('Montage', mWidth, mHeight) then
  1365.             exit(MakeMontage);
  1366.         MontageInfo := info;
  1367.         SaveGDevice := GetGDevice;
  1368.         SetGDevice(osGDevice);
  1369.         SetPort(GrafPtr(info^.osPort));
  1370.         pmForeColor(ForegroundIndex);
  1371.         dPort := info^.osPort;
  1372.         dLeft := 0;
  1373.         dTop := 0;
  1374.         sPort := StackInfo^.osPort;
  1375.         sRect := StackInfo^.PicRect;
  1376.         i := FirstSlice;
  1377.         while i <= LastSlice do begin
  1378.                 Info := StackInfo;
  1379.                 SelectSlice(i);
  1380.                 SetRect(dRect, dLeft, dTop, dLeft + dWidth, dTop + DHeight);
  1381.                 CopyPics(sPort, dPort, sRect, dRect);
  1382.                 info := MontageInfo;
  1383.                 if gNumberSlices then begin
  1384.                         MoveTo(dLeft + (dWidth div 2) - 3, dTop + dHeight - 9);
  1385.                         NumToString(i, str);
  1386.                         loc.h := dLeft + (dWidth div 2) - 3;
  1387.                         loc.v := dTop + dHeight - 5;
  1388.                         DrawTextString(str, loc, TeJustCenter);
  1389.                     end;
  1390.                 if gBorders then with dRect do begin
  1391.                     PenSize(LineWidth, LineWidth);
  1392.                     MoveTo(left,bottom);
  1393.                     LineTo(left,top);
  1394.                     LineTo(right,top);
  1395.                     LineTo(right,bottom);
  1396.                     LineTo(left,bottom);
  1397.                 end;
  1398.                 UpdateScreen(dRect);
  1399.                 dLeft := dLeft + dWidth;
  1400.                 if (dLeft + dWidth) > mWidth then begin
  1401.                         dLeft := 0;
  1402.                         dTop := dTop + dHeight;
  1403.                     end;
  1404.                 i := i + inc;
  1405.             end;
  1406.         if gBorders then
  1407.             FrameRect(info^.PicRect);
  1408.         SetGDevice(SaveGDevice);
  1409.         info := StackInfo;
  1410.         SelectSlice(info^.StackInfo^.CurrentSlice);
  1411.         info := MontageInfo;
  1412.         if info^.PixMapSize > UndoBufSize then
  1413.             PutWarning;
  1414.     end;
  1415.  
  1416.  
  1417.     procedure CopyRGBToPixMap (pmap: PixMapHandle);
  1418.         type
  1419.             LongPtr = ^LongInt;
  1420.         var
  1421.             row, i, width, WatchRate: integer;
  1422.             RedLine, GreenLine, BlueLine: LineType;
  1423.             Pixel, RowOffset: LongInt;
  1424.             pmapPtr: ptr;
  1425.             LPtr, RowStart: LongPtr;
  1426.     begin
  1427.         with info^ do begin
  1428.                 pmapPtr := GetPixBaseAddr(pmap);
  1429.                 if pmapPtr = nil then
  1430.                     exit(CopyRGBToPixMap);
  1431.                 LPtr := LongPtr(pmapPtr);
  1432.                 RowStart := LPtr;
  1433.                 RowOffset := band(pmap^^.RowBytes, $3FFF);
  1434.                 width := PicRect.right;
  1435.                 WatchRate := 40000 div PixelsPerLine;
  1436.                 for row := 0 to nLines - 1 do begin
  1437.                         if (row mod WatchRate) = 0 then
  1438.                             ShowAnimatedWatch;
  1439.                         SelectSlice(1);
  1440.                         GetLine(0, row, width, RedLine);
  1441.                         SelectSlice(2);
  1442.                         GetLine(0, row, width, GreenLine);
  1443.                         SelectSlice(3);
  1444.                         GetLine(0, row, width, BlueLine);
  1445.                         LPtr := RowStart;
  1446.                         for i := 0 to PixelsPerLine - 1 do begin
  1447.                                 pixel := -1;
  1448.                                 pixel := RedLine[i];
  1449.                                 pixel := bor(bsl(pixel, 8), GreenLine[i]);
  1450.                                 pixel := bor(bsl(pixel, 8), blueLine[i]);
  1451.                                 LPtr^ := BitNot(pixel);
  1452.                                 LPtr := LongPtr(ord4(LPtr) + 4);
  1453.                             end;
  1454.                         RowStart := LongPtr(ord4(RowStart) + RowOffset);
  1455.                     end;
  1456.                 SelectSlice(StackInfo^.CurrentSlice);
  1457.             end; {with}
  1458.     end;
  1459.  
  1460.  
  1461.     function DoColorOptions: boolean;
  1462.         const
  1463.             ExistingID = 4;
  1464.             SystemID = 5;
  1465.             CustomID = 6;
  1466.             DitherID = 7;
  1467.         var
  1468.             mylog: DialogPtr;
  1469.             item: integer;
  1470.  
  1471.         procedure UpdateButtons;
  1472.         begin
  1473.             SetDlogItem(mylog, ExistingID, ord(RGBLut = ExistingLUT));
  1474.             SetDlogItem(mylog, SystemID, ord(RGBLut = SystemLUT));
  1475.             SetDlogItem(mylog, CustomID, ord(RGBLut = CustomLUT));
  1476.         end;
  1477.  
  1478.     begin
  1479.         InitCursor;
  1480.         mylog := GetNewDialog(160, nil, pointer(-1));
  1481.         SetDlogItem(mylog, DitherID, ord(DitherColor));
  1482.         UpdateButtons;
  1483.         OutlineButton(MyLog, ok, 16);
  1484.         repeat
  1485.             ModalDialog(nil, item);
  1486.             if item = DitherID then begin
  1487.                     DitherColor := not DitherColor;
  1488.                     SetDlogItem(mylog, DitherID, ord(DitherColor));
  1489.                 end;
  1490.             if item = ExistingID then begin
  1491.                     RGBLut := ExistingLUT;
  1492.                     UpdateButtons
  1493.                 end;
  1494.             if item = SystemID then begin
  1495.                     RGBLut := SystemLUT;
  1496.                     UpdateButtons;
  1497.                     DitherColor := true;
  1498.                     SetDlogItem(mylog, DitherID, ord(DitherColor));
  1499.                 end;
  1500.             if item = CustomID then begin
  1501.                     RGBLut := CustomLUT;
  1502.                     UpdateButtons
  1503.                 end;
  1504.         until (item = ok) or (item = cancel);
  1505.         DisposeDialog(mylog);
  1506.         DoColorOptions := item <> cancel;
  1507.     end;
  1508.  
  1509.  
  1510.  
  1511.     procedure ConvertRGBToEightBitColor (Capturing: boolean);
  1512.         var
  1513.             err: QDErr;
  1514.             err2: OSErr;
  1515.             osGWorld: GWorldPtr;
  1516.             flags: GWorldFlags;
  1517.             pmap: PixMapHandle;
  1518.             pRect: rect;
  1519.             thePictInfo: PictInfo;
  1520.             CopyMode, SamplingMethod: integer;
  1521.             UpdateNeeded: boolean;
  1522.             SaveGDevice: GDHandle;
  1523.     begin
  1524.         if not System7 then begin
  1525.                 PutError('You must be running System 7 to do 24 to 8-bit color conversions.');
  1526.                 exit(ConvertRGBToEightBitColor);
  1527.             end;
  1528.         with info^ do begin
  1529.                 if StackInfo^.nSlices <> 3 then begin
  1530.                         PutError('24 to 8-bit color conversion requires a three slice (red, green and blue) stack as input.');
  1531.                         exit(ConvertRGBToEightBitColor);
  1532.                     end;
  1533.                 if StackInfo^.StackType <> rgbStack then begin;
  1534.                     StackInfo^.StackType := rgbStack;
  1535.                     UpdateTitleBar;
  1536.                 end;
  1537.                 if Capturing then begin
  1538.                         DitherColor := true;
  1539.                         RGBLut := CustomLUT;
  1540.                     end
  1541.                 else if not macro then begin
  1542.                         if not DoColorOptions then
  1543.                             exit(ConvertRGBToEightBitColor);
  1544.                     end;
  1545.                 flags := 0; {ppc-bug}
  1546.                 SaveGDevice := GetGDevice;
  1547.                 SetGDevice(osGDevice);
  1548.                 err := NewGWorld(osGWorld, 32, PicRect, nil, nil, flags);
  1549.                 SetGDevice(SaveGDevice);
  1550.                 if err <> NoErr then begin
  1551.                         PutMemoryAlert;
  1552.                         exit(ConvertRGBToEightBitColor);
  1553.                     end;
  1554.                 pmap := GetGWorldPixMap(osGWorld);
  1555.                 if not LockPixels(pmap) then
  1556.                     begin
  1557.                         DisposeGWorld(osGWorld);
  1558.                         exit(ConvertRGBToEightBitColor);
  1559.                     end;
  1560.                 CopyRGBToPixMap(pmap);
  1561.                 pRect := PicRect;
  1562.             end; {with}
  1563.         UpdateNeeded := true;
  1564.         if Activate('Indexed Color') then begin
  1565.                 if (info^.PixelsPerLine <> pRect.right) or (info^.nLines <> pRect.bottom) then begin
  1566.                         if not NewPicWindow('Indexed Color', pRect.right, pRect.bottom) then
  1567.                             begin
  1568.                                 DisposeGWorld(osGWorld);
  1569.                                 exit(ConvertRGBToEightBitColor);
  1570.                             end;
  1571.                         UpdateNeeded := false;
  1572.                     end
  1573.             end
  1574.         else begin
  1575.                 if not NewPicWindow('Indexed Color', pRect.right, pRect.bottom) then
  1576.                     begin
  1577.                         DisposeGWorld(osGWorld);
  1578.                         exit(ConvertRGBToEightBitColor);
  1579.                     end;
  1580.                 UpdateNeeded := false;
  1581.             end;
  1582.         if RGBLut = SystemLUT then
  1583.             SwitchColorTables(SystemPaletteItem, false)
  1584.         else if RGBLut = CustomLut then begin
  1585.                 if OptionKeyWasDown then
  1586.                     SamplingMethod := PopularMethod
  1587.                 else
  1588.                     SamplingMethod := SystemMethod;
  1589.                 err2 := GetPixMapInfo(pmap, thePictInfo, ReturnColorTable, 256, SamplingMethod, 0);
  1590.                 LoadColorTable(thePictInfo.theColorTable);
  1591.             end;
  1592.         SetForegroundColor(BlackIndex);
  1593.         SetBackgroundColor(WhiteIndex);
  1594.         if DitherColor then
  1595.             CopyMode := DitherCopy
  1596.         else
  1597.             CopyMode := SrcCopy;
  1598.         SetGDevice(osGDevice);
  1599.         SetPort(GrafPtr(Info^.osPort));
  1600.         CopyBits(BitMapHandle(pmap)^^, BitMapHandle(info^.osPort^.PortPixMap)^^, pRect, pRect, CopyMode, nil);
  1601.         DisposeGWorld(osGWorld);
  1602.         SetGDevice(SaveGDevice);
  1603.         if UpdateNeeded then
  1604.             UpdatePicWindow;
  1605.     end;
  1606.  
  1607.  
  1608.     function MakeRGBStack (name: str255): boolean;
  1609.         var
  1610.             ignore: integer;
  1611.     begin
  1612.         MakeRGBStack := false;
  1613.         if not Duplicate(name, false) then
  1614.             exit(MakeRGBStack);
  1615.         if not MakeStackFromWindow then
  1616.             exit(MakeRGBStack);
  1617.         if not AddSlice(false) then begin
  1618.                 info^.changes := false;
  1619.                 ignore := CloseAWindow(info^.wptr);
  1620.                 exit(MakeRGBStack);
  1621.             end;
  1622.         if not AddSlice(false) then begin
  1623.                 info^.changes := false;
  1624.                 ignore := CloseAWindow(info^.wptr);
  1625.                 exit(MakeRGBStack);
  1626.             end;
  1627.         MakeRGBStack := true;
  1628.     end;
  1629.  
  1630.  
  1631.     procedure ConvertEightBitColorToRGB;
  1632.         var
  1633.             width, height, i, row: integer;
  1634.             srcLine, rLine, gLine, bLine: LineType;
  1635.             rLut, gLUT, bLUT: packed array[0..255] of byte;
  1636.             value: byte;
  1637.     begin
  1638.         if isGrayscaleLUT then begin
  1639.                 PutError('8-bit color to RGB conversion requires a color image.');
  1640.                 exit(ConvertEightBitColorToRGB);
  1641.             end;
  1642.         KillRoi;
  1643.         if not MakeRGBStack(concat(info^.title, ' (RGB)')) then
  1644.             exit(ConvertEightBitColorToRGB);
  1645.         LoadLUT(Info^.cTable);
  1646.         for i := 0 to 255 do
  1647.             with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin
  1648.                     rLUT[i] := BitNot(band(bsr(red, 8), 255));
  1649.                     gLUT[i] := BitNot(band(bsr(green, 8), 255));
  1650.                     bLUT[i] := BitNot(band(bsr(blue, 8), 255));
  1651.                 end;
  1652.         width := info^.PixelsPerLine;
  1653.         height := info^.nLines;
  1654.         for row := 0 to height - 1 do begin
  1655.                 SelectSlice(1);
  1656.                 GetLine(0, row, width, srcLine);
  1657.                 for i := 0 to width - 1 do begin
  1658.                         value := srcLine[i];
  1659.                         rLine[i] := rLUT[value];
  1660.                         gLine[i] := gLUT[value];
  1661.                         bLine[i] := bLUT[value];
  1662.                     end;
  1663.                 PutLine(0, row, width, rLine);
  1664.                 SelectSlice(2);
  1665.                 PutLine(0, row, width, gLine);
  1666.                 SelectSlice(3);
  1667.                 PutLine(0, row, width, bLine);
  1668.             end;
  1669.         with Info^.StackInfo^ do begin
  1670.                 CurrentSlice := 1;
  1671.                 SelectSlice(CurrentSlice);
  1672.                 StackType := rgbStack;
  1673.                 UpdateTitleBar;
  1674.             end;
  1675.         ResetGrayMap;
  1676.     end;
  1677.  
  1678.  
  1679.     procedure CopyGWorldToStack;
  1680.     {Copies the color image stored in the 32-bit GWorld used by QuickTime
  1681.      video digitizers to a 3 slice (RGB) stack.}
  1682.         type
  1683.             LongPtr = ^LongInt;
  1684.         var
  1685.             row, i, width, WatchRate: integer;
  1686.             RedLine, GreenLine, BlueLine: LineType;
  1687.             Pixel, RowOffset: LongInt;
  1688.             pmapPtr: ptr;
  1689.             LPtr, RowStart: LongPtr;
  1690.     begin
  1691.         if fgPixMap^^.pixelSize <> 32 then begin
  1692.             PutError('RGB capture requires a 24-bit digitizer.');
  1693.             DigitizerMode := digitizeColor;
  1694.             exit(CopyGWorldToStack);
  1695.         end;
  1696.         if not MakeRGBStack(StringOf('RGB-', nPics:1)) then
  1697.             exit(CopyGWorldToStack);
  1698.         with info^ do begin
  1699.             pmapPtr := GetPixBaseAddr(fgPixMap);
  1700.             if pmapPtr = nil then
  1701.                 exit(CopyGWorldToStack);
  1702.             LPtr := LongPtr(pmapPtr);
  1703.             RowStart := LPtr;
  1704.             RowOffset := band(fgPixMap^^.RowBytes, $3FFF);
  1705.             width := PicRect.right;
  1706.             WatchRate := 40000 div PixelsPerLine;
  1707.             for row := 0 to nLines - 1 do begin
  1708.                     if (row mod WatchRate) = 0 then
  1709.                         ShowAnimatedWatch;
  1710.                     LPtr := RowStart;
  1711.                     for i := 0 to PixelsPerLine - 1 do begin
  1712.                             pixel := BitNot(LPtr^);
  1713.                             blueLine[i] := band(pixel, 255);
  1714.                             pixel := bsr(pixel, 8);
  1715.                             greenLine[i] := band(pixel, 255);
  1716.                             pixel := bsr(pixel, 8);
  1717.                             redLine[i] := band(pixel, 255);
  1718.                             LPtr := LongPtr(ord4(LPtr) + 4);
  1719.                         end;
  1720.                     RowStart := LongPtr(ord4(RowStart) + RowOffset);
  1721.                     SelectSlice(1);
  1722.                     PutLine(0, row, width, RedLine);
  1723.                     SelectSlice(2);
  1724.                     PutLine(0, row, width, GreenLine);
  1725.                     SelectSlice(3);
  1726.                     PutLine(0, row, width, BlueLine);
  1727.                 end;
  1728.             with Info^.StackInfo^ do begin
  1729.                     CurrentSlice := 1;
  1730.                     SelectSlice(CurrentSlice);
  1731.                     StackType := rgbStack;
  1732.                     UpdateTitleBar;
  1733.                 end;
  1734.             ResetGrayMap;
  1735.         end; {with}
  1736.     end;
  1737.  
  1738.  
  1739.     procedure CaptureVDigColor;
  1740.         var
  1741.             err: OSErr;
  1742.             pRect: rect;
  1743.             thePictInfo: PictInfo;
  1744.             SaveGDevice: GDHandle;
  1745.     begin
  1746.         if DigitizerMode = digitizeGrayscale then begin
  1747.             PutError('To capture color, "8-bit Color" or "RGB Color" must be selected in Video Control.');
  1748.             exit(CaptureVDigColor);
  1749.         end;
  1750.         if not digitizing then begin
  1751.             if info^.PictureType <> FrameGrabberType then
  1752.                 SelectCameraWindow;
  1753.             CaptureAndDisplayFrame;
  1754.         end;
  1755.         if fgPixMap = nil then
  1756.             exit(CaptureVDigColor);
  1757.         SaveGDevice := GetGDevice;
  1758.         err := GetPixMapInfo(fgPixMap, thePictInfo, ReturnColorTable, 256, SystemMethod, 0);
  1759.         if err = noErr then begin
  1760.             LoadColorTable(thePictInfo.theColorTable);
  1761.             SetForegroundColor(BlackIndex);
  1762.             SetBackgroundColor(WhiteIndex);
  1763.             SetGDevice(osGDevice);
  1764.             SetPort(GrafPtr(Info^.osPort));
  1765.             with info^ do
  1766.                 CopyBits(BitMapHandle(fgPixMap)^^, BitMapHandle(osPort^.PortPixMap)^^, picRect, picRect, DitherCopy, nil);
  1767.             SetGDevice(SaveGDevice);
  1768.             UpdatePicWindow;
  1769.             DrawLUT;
  1770.         end;
  1771.         if DigitizerMode = digitizeRGB then
  1772.             CopyGWorldToStack;
  1773.     end;
  1774.  
  1775.  
  1776.     procedure CaptureColor;
  1777.         var
  1778.             MainDevice: GDHandle;
  1779.             SourcePixMap: PixMapHandle;
  1780.             frame, width, height, SaveChannel: integer;
  1781.             frect: rect;
  1782.     begin
  1783.         with info^ do
  1784.             if PictureType <> FrameGrabberType then begin
  1785.                     PutError('You must be capturing to capture color.');
  1786.                     AbortMacro;
  1787.                     exit(CaptureColor);
  1788.                 end;
  1789.         StopDigitizing;
  1790.         if frameGrabber = QTvdig then begin
  1791.             CaptureVDigColor;
  1792.             exit(CaptureColor);
  1793.         end;
  1794.         with info^.PicRect do begin
  1795.                 width := right - left;
  1796.                 height := bottom - top;
  1797.             end;
  1798.         if Activate('RGB') then
  1799.             with info^.PicRect do begin
  1800.                     if ((right - left) <> width) or ((bottom - top) <> height) then
  1801.                         if not MakeRGBStack('RGB') then
  1802.                             exit(CaptureColor);
  1803.                 end
  1804.         else if not MakeRGBStack('RGB') then
  1805.             exit(CaptureColor);
  1806.         ShowWatch;
  1807.         SourcePixMap := fgPixMap;
  1808.         ResetFrameGrabber;
  1809.         with frect do begin
  1810.                 left := 0;
  1811.                 top := 0;
  1812.                 right := left + width;
  1813.                 bottom := top + height;
  1814.             end;
  1815.         ShowTriggerMessage;
  1816.         SaveChannel := VideoChannel;
  1817.         with info^, info^.StackInfo^ do begin
  1818.                 for frame := 1 to 3 do begin
  1819.                         if FrameGrabber = QuickCapture then begin
  1820.                                 case frame of
  1821.                                     1: 
  1822.                                         VideoChannel := 1; {Green}
  1823.                                     2: 
  1824.                                         VideoChannel := 0;  {Red}
  1825.                                     3: 
  1826.                                         VideoChannel := 2;  {Blue}
  1827.                                 end;
  1828.                                 ResetFrameGrabber;
  1829.                                 repeat
  1830.                                 until band(ControlReg^, $8) = 0; {mux channel not busy}
  1831.                             end
  1832.                         else begin
  1833.                                 VideoChannel := frame - 1;
  1834.                                 ResetFrameGrabber;
  1835.                             end;
  1836.                         if VideoControl <> nil then
  1837.                             ShowChannel;
  1838.                         CurrentSlice := frame;
  1839.                         SelectSlice(CurrentSlice);
  1840.                         GetFrame;
  1841.                         CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
  1842.                     end; {for}
  1843.                 CurrentSlice := 1;
  1844.                 SelectSlice(CurrentSlice);
  1845.                 UpdateTitleBar;
  1846.             end; {with}
  1847.         VideoChannel := SaveChannel;
  1848.         if VideoControl <> nil then
  1849.             ShowChannel;
  1850.         ConvertRGBToEightBitColor(true);
  1851.     end;
  1852.  
  1853.  
  1854.     procedure AverageSlices;
  1855.         const
  1856.             MaxWidth = 2048;
  1857.         var
  1858.             slices, sRow, aRow, slice, i, SaveSlice: integer;
  1859.             width, height, hstart, vStart: integer;
  1860.             OldInfo, NewInfo: InfoPtr;
  1861.             aLine: LineType;
  1862.             mask: rect;
  1863.             sum: array[0..MaxWidth] of LongInt;
  1864.             AutoSelectAll: boolean;
  1865.             SlicesDiv2:LongInt;
  1866.     begin
  1867.         OldInfo := Info;
  1868.         with info^ do begin
  1869.                 if StackInfo = nil then begin
  1870.                         PutError('Average Slices requires a stack.');
  1871.                         AbortMacro;
  1872.                         exit(AverageSlices);
  1873.                     end;
  1874.                 AutoSelectAll := not Info^.RoiShowing;
  1875.                 if AutoSelectAll then
  1876.                     SelectAll(true);
  1877.                 with RoiRect do begin
  1878.                         hStart := left;
  1879.                         vStart := top;
  1880.                         width := right - left;
  1881.                         height := bottom - top;
  1882.                     end;
  1883.                 if width > MaxWidth then begin
  1884.                         PutError(concat('NIH Image can''t average selections wider than ', Long2str(MaxWidth), ' pixels.'));
  1885.                         AbortMacro;
  1886.                         exit(AverageSlices);
  1887.                     end;
  1888.                 with StackInfo^ do begin
  1889.                         slices := StackInfo^.nSlices;
  1890.                         SaveSlice := CurrentSlice;
  1891.                     end;
  1892.                 if not NewPicWindow('Average', width, height) then begin
  1893.                         AbortMacro;
  1894.                         exit(AverageSlices);
  1895.                     end;
  1896.             end;
  1897.         info^.changes := true;
  1898.         NewInfo := Info;
  1899.         aRow := 0;
  1900.         SlicesDiv2:=slices div 2; {Needed for rounding}
  1901.         for sRow := vStart to vStart + height - 1 do begin
  1902.                 info := OldInfo;
  1903.                 for i := 0 to width - 1 do
  1904.                     sum[i] := 0;
  1905.                 for slice := 1 to slices do begin
  1906.                         SelectSlice(slice);
  1907.                         GetLine(hStart, sRow, width, aLine);
  1908.                         for i := 0 to width - 1 do
  1909.                             sum[i] := sum[i] + aLine[i];
  1910.                     end;
  1911.                 for i := 0 to width - 1 do
  1912.                     aLine[i] := (sum[i]+SlicesDiv2) div slices;
  1913.                 info := NewInfo;
  1914.                 PutLine(0, aRow, width, aLine);
  1915.                 SetRect(mask, 0, aRow, width, aRow + 1);
  1916.                 aRow := aRow + 1;
  1917.                 UpdateScreen(mask);
  1918.                 if CommandPeriod then
  1919.                     leave;
  1920.             end;
  1921.         info := OldInfo;
  1922.         SelectSlice(SaveSlice);
  1923.         if AutoSelectAll then
  1924.             KillRoi;
  1925.         info:=NewInfo;
  1926.     end;
  1927.  
  1928.  
  1929.     procedure ConvertRGBToHSV;
  1930.         const
  1931.             MaxSaturation = 255;
  1932.             MaxValue = 255;
  1933.         var
  1934.             width, height, i, row, mark: integer;
  1935.             rLine, gLine, bLine, hLine, sLine, vLine: LineType;
  1936.             delta, min, max, R, G, B, H, S, V: integer;
  1937.             tmp: longint;
  1938.             UpdateR: rect;
  1939.  
  1940.         function Max3 (a, b, c: integer): integer;
  1941.             var
  1942.                 TempMax: integer;
  1943.         begin
  1944.             if (a > b) then
  1945.                 TempMax := a
  1946.             else
  1947.                 TempMax := b;
  1948.             if (TempMax > c) then
  1949.                 Max3 := TempMax
  1950.             else
  1951.                 Max3 := c;
  1952.         end;
  1953.  
  1954.         function Min3 (a, b, c: integer): integer;
  1955.             var
  1956.                 TempMin: integer;
  1957.         begin
  1958.             if (a < b) then
  1959.                 TempMin := a
  1960.             else
  1961.                 TempMin := b;
  1962.             if (TempMin < c) then
  1963.                 Min3 := TempMin
  1964.             else
  1965.                 Min3 := c;
  1966.         end;
  1967.  
  1968.     begin
  1969.         with info^ do begin
  1970.                 if StackInfo^.nSlices <> 3 then begin
  1971.                         PutError('RGB to HSV color conversion requires a three slice(red, green and blue) stack as input.');
  1972.                         exit(ConvertRGBToHSV);
  1973.                     end;
  1974.                 if Changes then begin
  1975.                         if PutMessageWithCancel('RGB to HSV color conversion is undoable.') = cancel then
  1976.                             exit(ConvertRGBToHSV);
  1977.                     end;
  1978.                 KillRoi;
  1979.                 with StackInfo^ do begin
  1980.                         CurrentSlice := 1;
  1981.                         SelectSlice(CurrentSlice);
  1982.                         UpdatePicWindow;
  1983.                     end;
  1984.                 SwitchColorTables(SpectrumItem, true);
  1985.                 title := 'HSV';
  1986.                 UpdateTitleBar;
  1987.                 width := PixelsPerLine;
  1988.                 height := nLines;
  1989.                 mark := 0;
  1990.                 ShowWatch;
  1991.                 for row := 0 to height - 1 do begin
  1992.                         SelectSlice(1);
  1993.                         GetLine(0, row, width, rLine);
  1994.                         SelectSlice(2);
  1995.                         GetLine(0, row, width, gLine);
  1996.                         SelectSlice(3);
  1997.                         GetLine(0, row, width, bLine);
  1998.                         for i := 0 to width - 1 do begin
  1999.                                 R := 255 - rLine[i];
  2000.                                 G := 255 - gLine[i];
  2001.                                 B := 255 - bLine[i];
  2002.                                 max := Max3(R, G, B);
  2003.                                 min := Min3(R, G, B);
  2004.                                 V := max;
  2005.                                 if max <> 0 then begin
  2006.                                         tmp := 255 * (max - min);
  2007.                                         S := (tmp + (tmp mod max)) div max;  {adding '(tmp mod max)' simulate rounding}
  2008.                                     end
  2009.                                 else
  2010.                                     S := 0;
  2011.                                 if S = 0 then
  2012.                                     H := 0  {undefined but, but select red }
  2013.                                 else begin
  2014.                                         delta := max - min;
  2015.                                         if R = max then begin
  2016.                                                 tmp := 85 * (G - B);
  2017.                                                 H := tmp div delta;
  2018.                                             end
  2019.                                         else if G = max then begin
  2020.                                                 tmp := 85 * (B - R);
  2021.                                                 H := 170 + tmp div delta;
  2022.                                             end
  2023.                                         else if B = max then begin
  2024.                                                 tmp := 85 * (R - G);
  2025.                                                 H := 340 + tmp div delta;
  2026.                                             end;
  2027.                                         H := H div 2;
  2028.                                         if H < 0 then
  2029.                                             H := H + 255
  2030.                                     end;
  2031.                                 if H = 0 then
  2032.                                     hLine[i] := 1
  2033.                                 else
  2034.                                     hLine[i] := H;
  2035.                                 sLine[i] := S;
  2036.                                 vLine[i] := 255 - V;
  2037.                             end;
  2038.                         SelectSlice(1);
  2039.                         PutLine(0, row, width, hLine);
  2040.                         if (row mod 10) = 0 then begin
  2041.                                 setrect(UpdateR, 0, mark, width - 1, row);
  2042.                                 mark := row;
  2043.                                 UpdateScreen(UpdateR);
  2044.                             end;
  2045.                         SelectSlice(2);
  2046.                         PutLine(0, row, width, sLine);
  2047.                         SelectSlice(3);
  2048.                         PutLine(0, row, width, vLine);
  2049.                     end;
  2050.                 SelectSlice(1);
  2051.                 StackInfo^.StackType := hsvStack;
  2052.                 UpdateTitleBar;
  2053.             end; {with}
  2054.         WhatToUndo := NothingToUndo;
  2055.     end;
  2056.  
  2057.  
  2058.     procedure DoStackInfo;
  2059.     const
  2060.         VolumeID = 5;
  2061.         MovieID = 6;
  2062.         RGBID = 7;
  2063.         HSVID = 8;
  2064.         SpacingID = 11;
  2065.         IntervalID = 12;
  2066.     var
  2067.         mylog: DialogPtr;
  2068.         item: integer;
  2069.         spacing, SaveSpacing, SaveInterval: extended;
  2070.         SaveType: StackTypeType;
  2071.         str: str255;
  2072.         
  2073.         procedure ShowStackType;
  2074.         begin
  2075.             With info^.StackInfo^ do begin
  2076.                 SetDlogItem(MyLog, VolumeID, ord(StackType = VolumeStack));
  2077.                 SetDlogItem(MyLog, MovieID, ord(StackType = MovieStack));
  2078.                 SetDlogItem(MyLog, RGBID, ord(StackType = rgbStack));
  2079.                 SetDlogItem(MyLog, HSVID, ord(StackType = hsvStack));
  2080.             end;
  2081.         end;
  2082.         
  2083.     begin
  2084.         With info^, info^.StackInfo^ do begin
  2085.             InitCursor;
  2086.             mylog := GetNewDialog(280, nil, pointer(-1));
  2087.             SaveType := StackType;
  2088.             SaveSpacing := SliceSpacing;
  2089.             SaveInterval := Frameinterval;
  2090.             ShowStackType;
  2091.             if SpatiallyCalibrated then begin
  2092.                 spacing := SliceSpacing / xScale;
  2093.                 str := xunit;
  2094.             end else begin
  2095.                 spacing := SliceSpacing;
  2096.                 str := 'pixels'
  2097.             end;
  2098.             SetDReal(MyLog, SpacingID, spacing, 3);
  2099.             ParamText(str, '', '', '');
  2100.             if Frameinterval < 99.0 then
  2101.                 SetDReal(MyLog, IntervalID, Frameinterval, 3)
  2102.             else
  2103.                 SetDReal(MyLog, IntervalID, Frameinterval, 0);
  2104.             SelectDialogItemText(MyLog, SpacingID, 0, 32767);
  2105.             OutlineButton(MyLog, ok, 16);
  2106.             repeat
  2107.                 ModalDialog(nil, item);
  2108.                 if (item >= VolumeID) and (item <= HSVID) then begin
  2109.                     case item of
  2110.                         VolumeID: StackType := VolumeStack;
  2111.                         MovieID: StackType := MovieStack;
  2112.                         rgbID: StackType := rgbStack;
  2113.                         hsvID: StackType := hsvStack;
  2114.                     end;
  2115.                     ShowStackType;
  2116.                   end;
  2117.                 if item = SpacingID then begin
  2118.                     spacing := GetDReal(MyLog, SpacingID);
  2119.                     if SpatiallyCalibrated then
  2120.                         SliceSpacing := spacing * xScale
  2121.                     else
  2122.                         SliceSpacing := spacing;
  2123.                 end;
  2124.                 if item = IntervalID then
  2125.                     Frameinterval := GetDReal(MyLog, IntervalID);
  2126.             until (item = ok) or (item = cancel);
  2127.             DisposeDialog(mylog);
  2128.             if item = cancel then begin
  2129.                 StackType := SaveType;
  2130.                 SliceSpacing := SaveSpacing;
  2131.                 Frameinterval := SaveInterval;
  2132.             end else
  2133.                 if ((StackType = rgbStack) or (StackType = hsvStack)) and (nSlices <> 3) then begin
  2134.                     PutError('RGB and HSV stacks must have three slices.');
  2135.                     StackType := SaveType;
  2136.                 end;
  2137.         end; {with}
  2138.         UpdateTitleBar;
  2139.     end;
  2140.  
  2141.  
  2142. end.